#!/usr/bin/env ruby
#-*- coding:utf-8 -*-

module YMMail
  require 'nokogiri'
  require 'open-uri'
  require 'curb'

  class Mail
    attr_reader :users, :groups
    def initialize account, passwd, domain
      @users = {}
      @groups = {}
      @c = Curl::Easy.new
      @c.timeout = 60
      @c.cookiejar = "cookie"
      @c.cookiefile = "cookie"
      @c.enable_cookies = true
      @c.ssl_verify_host = 0
      @c.ssl_verify_peer = false
      #@c.verbose = true
      @timestamp = nil
      @domain = domain
      @account = account
      login(account, passwd, domain)
      parse_user_list
    end

    def user_list
      puts "总共 #{@users.length} 个用户"
      @users.each do |k,v|
        puts "#{k}  #{v[:name]}  #{v[:phone]}  #{v[:last_login]}  #{v[:uid]}"
      end
    end
    def group_list
      puts "总共 #{@groups.length} 个组"
      @groups.each do |k,v|
        puts "#{k}  #{v}"
      end
    end

    def delete_user name
      if !@timestamp || !@users.include?(name) then
        return nil
      end
      @c.url = "https://app.ym.163.com/ym/action/account/delete?aid=#{@timestamp}"
      @c.headers = {"Referer"=> "https://app.ym.163.com/ym/action/account/list?aid=#{@timestamp}"}
      @c.post_body = URI.encode_www_form({"account_id"=> @users[name][:uid]})
      @c.perform
      while @c.response_code == 302
        @c.url = @c.redirect_url
        @c.perform
      end
      if @c.url.start_with? "https://app.ym.163.com/ym/" then
        html = Nokogiri::HTML @c.body_str
        tip_err = html.xpath('//div[@id="tip_err"]').text.strip
        if tip_err != "" then
          puts tip_err
          return nil
        end
        @users.delete name
        puts "删除用户: #{name}"
        return name
      end
    end
    def add_user nickname, username, passwd, mobile=""
      if !@timestamp || @users.include?(username) then
        return nil
      end
      @c.url = "https://app.ym.163.com/ym/action/account/createAccount?aid=#{@timestamp}"
      @c.headers = {"Referer"=> "https://app.ym.163.com/ym/action/account/list?aid=#{@timestamp}"}
      @c.post_body = URI.encode_www_form({
        "nickname"=> nickname, "account_name"=> username,
        "pass_re"=> passwd, "mobile"=> mobile, "u_id"=> "0",
      })
      @c.perform
      while @c.response_code == 302
        @c.url = @c.redirect_url
        @c.perform
      end
      if @c.url.start_with? "https://app.ym.163.com/ym/" then
        #File.write 'page5.html', @c.body_str
        html = Nokogiri::HTML @c.body_str
        tip_err = html.xpath('//div[@id="tip_err"]').text.strip
        if tip_err != "" then
          puts tip_err
          return nil
        end
        em = html.xpath('//div[@class="ym-cont"]//div[@class="info-show"]//em[@class="txt-succ"]')
        if em.length > 0 then
          puts "添加用户: #{username}"
          @users.clear
          parse_user_list
          puts "激活用户: #{username}"
          active_account username, passwd, @domain
        end
        return username
      end
    end

    def add_group name
      if !@timestamp || @groups.include?(name) then
        return nil
      end
      @c.url = "https://app.ym.163.com/ym/action/dept/create?aid=#{@timestamp}"
      @c.headers = {"Referer"=> "https://app.ym.163.com/ym/action/account/list?aid=#{@timestamp}"}
      @c.post_body = URI.encode_www_form({"u_name"=> name})
      @c.perform
      while @c.response_code == 302
        @c.url = @c.redirect_url
        @c.perform
      end
      if @c.url.start_with? "https://app.ym.163.com/ym/" then
        html = Nokogiri::HTML @c.body_str
        li = html.xpath '//div[@class="ym-cont"]/table//ul[@id="dept_list"]/li[@title="%s"]' % [name]
        tip_err = html.xpath('//div[@id="tip_err"]').text.strip
        if tip_err != "" then
          puts tip_err
        end
        if li.length > 0 then
          @groups[name] = li.attribute('uid').value
          puts "添加组: #{name}"
        end
        return name
      end
    end
    def delete_group name
      if !@timestamp || !@groups.include?(name) then
        return nil
      end
      @c.url = "https://app.ym.163.com/ym/action/dept/delete?aid=#{@timestamp}"
      @c.headers = {"Referer"=> "https://app.ym.163.com/ym/action/account/list?aid=#{@timestamp}"}
      @c.post_body = URI.encode_www_form({"u_id"=> @groups[name]})
      @c.perform
      while @c.response_code == 302
        @c.url = @c.redirect_url
        @c.perform
      end
      if @c.url.start_with? "https://app.ym.163.com/ym/" then
        html = Nokogiri::HTML @c.body_str
        li = html.xpath '//div[@class="ym-cont"]/table//ul[@id="dept_list"]/li[@title="%s"]' % [name]
        tip_err = html.xpath('//div[@id="tip_err"]').text.strip
        if tip_err != "" then
          puts tip_err
        end
        if li.length == 0 then
          @groups.delete name
          puts "删除组: #{name}"
          return name
        end
      end
    end

    def parse_user_list uri=nil, parse_group=true
      c = Curl::Easy.new
      c.timeout = 60
      c.cookiejar = "cookie"
      c.cookiefile = "cookie"
      c.enable_cookies = true
      c.ssl_verify_host = 0
      c.ssl_verify_peer = false
      if uri then 
        c.url = uri
      else
        c.url = "https://app.ym.163.com/ym/action/account/list?aid=#{@timestamp}"
      end
      c.perform
      #File.write 'page3.html', c.body_str
      html = Nokogiri::HTML c.body_str
      c.close

      ym = html.xpath '//div[@class="ym-cont"]'
      if parse_group then
        @groups.clear
        ym.xpath('table//ul[@id="dept_list"]/li').each do |li|    # 联系组
          gid = li.attribute('uid').value
          gname = li.xpath('span').text.strip
          @groups[gname] = gid
        end
      end
      user_list = ym.xpath('table//div[@class="manage-list"]/table/tbody/tr')
      user_list.each do |tr|
        td = tr.xpath 'td'
        # name  email phone login_time  operate
        name = td[1].text
        email = td[1].text.split("@#{@domain}")[0]
        phone = td[2].text
        last_login = td[3].text
        uid = td[4].xpath('a')[0].attribute('href').value.match(/account_id=(\d+)/)[-1]
        @users[email] = {:name=> name, :phone=> phone, :last_login=> last_login, :uid=> uid}
      end
      next_page = ym.xpath('table//div[@id="pages"]/a')[3]
      if next_page
        l = URI.parse(next_page.attribute('href').value).query
      else
        l = nil
      end
      if l              # 下一页
        q = l.split('&')
        q.delete_if { |x| x.match(/^u_id=/) }
        l = q.join('&')
        parse_user_list "https://app.ym.163.com/ym/action/account/list?#{l}", false
      end
    end

    def active_account account, passwd, domain
      c = Curl::Easy.new
      c.timeout = 60
      c.cookiejar = "cookie1"
      c.cookiefile = "cookie1"
      c.enable_cookies = true
      c.ssl_verify_host = 0
      c.ssl_verify_peer = false
      data = {
        "account" => account,
        "password" => passwd,
        "ssl" => "1",
        "username" => account,
        "userAtDomain" => account,
        "account_name" => account,
        "domain" => domain
      }
      c.url = "https://entry.ym.163.com/login/login"
      c.post_body = URI.encode_www_form(data)
      c.perform
      c.post_body = nil
      while c.response_code == 302
        c.headers = {"Referer"=> c.url}
        c.url = c.redirect_url
        c.perform
      end
      if c.url.start_with? "http://entry.ym.163.com/entry/hmaildoor" then       # js跳转
        h = Nokogiri::HTML c.body_str
        c.url = h.xpath('//head/script').text.strip.match(/location.href="(http.+)";/)[1]
        c.headers = {"Referer"=> c.url}
        c.perform
      end
        
      if c.url.start_with? "http://app.ym.163.com/ym/passchange.jsp" then       # 修改密码
        h = Nokogiri::HTML c.body_str
        c.headers = {"Referer"=> c.url}
        c.url = h.xpath('//form').attribute('action').value
        data = {
          "username"=> account,
          "domain"=> domain,
          "password"=> passwd,
          "cpassword"=> passwd,
          "confirm"=> "accept"
        }
        c.post_body = URI.encode_www_form(data)
        c.perform
        c.post_body = nil
        while c.response_code == 302
          c.headers = {"Referer"=> c.url}
          c.url = c.redirect_url
          c.perform
        end
      end
      puts "finish: #{c.url}"
      finish_url = c.url
      c.close
      if finish_url.start_with? "http://mail.ym.163.com/" then
        return true
      end
    end

    private
      def login account, passwd, domain
        # login
        data = {
          "account" => account,
          "password" => passwd,
          "ssl" => "1",
          "username" => account,
          "userAtDomain" => account,
          "account_name" => account,
          "domain" => domain
        }
        @c.url = "https://entry.ym.163.com/login/login"
        @c.post_body = URI.encode_www_form(data)
        @c.perform
        #File.write 'page1.html', @c.body_str
        # Redirect to: http://entry.ym.163.com/entry/hmaildoor?uid=admin@xefan.com&node=ym&type=web&pc=0&ps=2&sess=null
        if @c.response_code == 200 then     # 登陆失败
          return false
        end
        if @c.response_code == 302 then
          @c.url = @c.redirect_url
          @c.perform
        end
        # Redirect to: http://app.ym.163.com/ym/action/adminlogin/login?aid=1394714304996&hl=zh_CN
        if @c.response_code == 302 then
          @c.url = @c.redirect_url
          @c.perform
        end
        # Redirect to: https://app.ym.163.com/ym/action/domain/index?aid=1394714305310
        if @c.response_code == 302 then
          @c.url = @c.redirect_url
          @c.perform
        end
        # 用户列表
        @timestamp = @c.url.match(/\d+$/)
      end
  end
end
